home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / mail / YAM22src.lha / YAM_TR.c < prev    next >
C/C++ Source or Header  |  2000-11-03  |  57KB  |  1,600 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 2000  Marcel Beck <mbeck@yam.ch>
  5.  
  6.  This program is free software; you can redistribute it and/or modify
  7.  it under the terms of the GNU General Public License as published by
  8.  the Free Software Foundation; either version 2 of the License, or
  9.  (at your option) any later version.
  10.  
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  
  16.  You should have received a copy of the GNU General Public License
  17.  along with this program; if not, write to the Free Software
  18.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20.  YAM Official Support Site :  http://www.yam.ch
  21.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  22.  
  23. ***************************************************************************/
  24.  
  25. #include "YAM.h"
  26.  
  27. /***************************************************************************
  28.  Module: Transfer
  29. ***************************************************************************/
  30.  
  31. /*** General connecting/disconnecting & transfer ***/
  32.  
  33. /// TR_IsOnline
  34. //  Checks if there's an online connection
  35. BOOL TR_IsOnline(void)
  36. {
  37.    BOOL isonline = FALSE;
  38.    struct Library *MiamiBase, *GenesisBase, *SoBase;
  39.  
  40.    if (C->IsOnlineCheck)
  41.    {
  42.       if (MiamiBase = OpenLibrary(MIAMINAME, 10))
  43.       {
  44.          isonline = MiamiIsOnline(*C->IOCInterface ? C->IOCInterface : NULL); CloseLibrary(MiamiBase);
  45.          return isonline;
  46.       }
  47.       else if (GenesisBase = OpenLibrary("genesis.library", 1))
  48.       {
  49.          isonline = IsOnline(*C->IOCInterface ? (long)C->IOCInterface : NULL); CloseLibrary(GenesisBase);
  50.          return isonline;
  51.       }
  52.    }
  53.    if (SoBase = OpenLibrary("bsdsocket.library", 2L))
  54.    {
  55.       isonline = TRUE; CloseLibrary(SoBase);
  56.    }
  57.    return isonline;
  58. }
  59. ///
  60. /// TR_CloseTCPIP
  61. //  Closes bsdsocket library
  62. void TR_CloseTCPIP(void)
  63. {
  64.    if (SocketBase) CloseLibrary(SocketBase);
  65.    SocketBase = NULL;
  66. }
  67. ///
  68. /// TR_OpenTCPIP
  69. //  Opens bsdsocket.library
  70. BOOL TR_OpenTCPIP(void)
  71. {
  72.    if (!TR_IsOnline()) return FALSE;
  73.    if (!SocketBase) SocketBase = OpenLibrary("bsdsocket.library", 2L);
  74.    return (BOOL)(SocketBase != NULL);
  75. }
  76. ///
  77. /// TR_Disconnect
  78. //  Terminates a connection
  79. void TR_Disconnect(void)
  80. {
  81.    if (G->TR_Socket != SMTP_NO_SOCKET)
  82.    {
  83.       Shutdown(G->TR_Socket, 2);
  84.       CloseSocket(G->TR_Socket);
  85.       G->TR_Socket = SMTP_NO_SOCKET;
  86.    }
  87. }
  88. ///
  89. /// TR_Connect
  90. //  Connects to a internet service
  91. int TR_Connect(char *host, int port)
  92. {
  93.    struct hostent *hostaddr;
  94.  
  95.    if (!(hostaddr = GetHostByName((STRPTR)host))) return -1;
  96.    G->TR_INetSocketAddr.sin_len = sizeof(G->TR_INetSocketAddr);
  97.    G->TR_INetSocketAddr.sin_family = 2;
  98.    G->TR_INetSocketAddr.sin_port = port;
  99.    G->TR_INetSocketAddr.sin_addr.s_addr = 0;
  100.    memcpy(&G->TR_INetSocketAddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
  101.    G->TR_Socket = Socket(hostaddr->h_addrtype, 1, 0);
  102.    if (G->TR_Socket == -1) { TR_Disconnect(); return -2; }
  103.    if (Connect(G->TR_Socket, (struct sockaddr *)&G->TR_INetSocketAddr, sizeof(G->TR_INetSocketAddr)) == -1) { TR_Disconnect(); return -3; }
  104.    return 0;
  105. }
  106. ///
  107. /// TR_RecvDat
  108. //  Receives data from a TCP/IP connection
  109. int TR_RecvDat(char *recvdata)                   /* success? */
  110. {
  111.    int len;
  112.  
  113.    DoMethod(G->App,MUIM_Application_InputBuffered);
  114.    if (G->TR_Socket == SMTP_NO_SOCKET) return 0;
  115.    len = Recv(G->TR_Socket, (STRPTR)recvdata, SIZE_LINE-1, 0);
  116.    recvdata[len] = '\0';
  117.    if (G->TR_Debug) printf("SERVER: %s", recvdata);
  118.    return len;
  119. }
  120. ///
  121. /// TR_SendDat
  122. //  Sends data through a TCP/IP connection
  123. BOOL TR_SendDat(char *senddata)                  /* success? */
  124. {
  125.    DoMethod(G->App,MUIM_Application_InputBuffered);
  126.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  127.    if (!senddata) return TRUE;
  128.    if (G->TR_Debug) printf("CLIENT: %s", senddata);
  129.    if (Send(G->TR_Socket, (STRPTR)senddata, strlen(senddata), 0) != -1) return TRUE;
  130.    return FALSE;
  131. }
  132. ///
  133. /// TR_SetWinTitle
  134. //  Sets the title of the transfer window
  135. void TR_SetWinTitle(BOOL from, char *host)
  136. {
  137.    sprintf(G->TR->WTitle, GetStr(from ? MSG_TR_MailTransferFrom : MSG_TR_MailTransferTo), host);
  138.    set(G->TR->GUI.WI, MUIA_Window_Title, G->TR->WTitle);
  139. }
  140. ///
  141.  
  142. /*** HTTP routines ***/
  143. /// TR_DownloadURL
  144. //  Downloads a file from the web using HTTP
  145. BOOL TR_DownloadURL(char *url0, char *url1, char *url2, char *filename)
  146. {
  147.    
  148.    BOOL success = FALSE, done = FALSE, noproxy = !*C->ProxyServer;
  149.    int l = 0, len, hport;
  150.    char buf[SIZE_LINE], url[SIZE_URL], host[SIZE_HOST], *port, *path, line[SIZE_DEFAULT], *bufptr;
  151.    FILE *out;
  152.  
  153.    G->Error = FALSE;
  154.    if (!strnicmp(url0,"http://",7)) strcpy(url, &url0[7]); else strcpy(url, url0);
  155.    if (url1)
  156.    {
  157.       if (url[strlen(url)-1] != '/') strcat(url, "/");
  158.       strcat(url, url1);
  159.    }
  160.    if (url2)
  161.    {
  162.       if (url[strlen(url)-1] != '/') strcat(url, "/");
  163.       strcat(url, url2);
  164.    }
  165.    if (path = strchr(url,'/')) *path++ = 0; else path = "";
  166.    strcpy(host, noproxy ? url : C->ProxyServer);
  167.    if (bufptr = strchr(host, ':')) { *bufptr++ = 0; hport = atoi(bufptr); }
  168.    else hport = noproxy ? 80 : 8080;
  169.    if (!TR_Connect(host, hport))
  170.    {
  171. /*
  172.       if (noproxy) sprintf(buf, "GET /%s HTTP/1.0\r\nHost: http://%s\r\n", path, host);
  173.       else if (port = strchr(url, ':'))
  174.       {
  175.          *port++ = 0;
  176.          sprintf(buf, "GET http://%s:%s/%s HTTP/1.0\r\nHost: http://%s\r\n", url, port, path, url);
  177.       }
  178.       else sprintf(buf, "GET http://%s/%s HTTP/1.0\r\nHost: http://%s\r\n", url, path, url);
  179.       sprintf(&buf[strlen(buf)], "From: %s\r\nUser-Agent: YAM %s\r\n\r\n", BuildAddrName(C->EmailAddress, C->RealName), __VERSION__);
  180. */
  181.       if (noproxy) sprintf(buf, "GET /%s HTTP/1.0\r\nHost: %s\r\n", path, host);
  182.       else if (port = strchr(url, ':'))
  183.       {
  184.          *port++ = 0;
  185.          sprintf(buf, "GET http://%s:%s/%s HTTP/1.0\r\nHost: %s\r\n", url, port, path, url);
  186.       }
  187.       else sprintf(buf, "GET http://%s/%s HTTP/1.0\r\nHost: %s\r\n", url, path, url);
  188.       sprintf(&buf[strlen(buf)], "From: %s\r\nUser-Agent: YAM %s\r\n\r\n", BuildAddrName(C->EmailAddress, C->RealName), __VERSION__);
  189.       if (TR_SendDat(buf))
  190.       {
  191.          len = TR_RecvDat(buf);
  192.          if (atoi(&buf[9]) == 200)
  193.          {
  194.             if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  195.             while (!G->Error)
  196.             {
  197.                for (; *bufptr; bufptr++)
  198.                {
  199.                   if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  200.                   if (*bufptr != '\n') continue;
  201.                   line[l] = 0; l = 0;
  202.                   if (line[0] == '\n') { done = TRUE; break; }
  203.                }
  204.                if (done) break;
  205.                if ((len = TR_RecvDat(buf)) <= 0) break;
  206.                bufptr = buf;
  207.             }
  208.             if (out = fopen(filename, "w"))
  209.             {
  210.                ++bufptr;
  211.                fwrite(bufptr, len-(bufptr-buf), 1, out);
  212.                while ((len = TR_RecvDat(buf)) > 0) fwrite(buf, len, 1, out);
  213.                fclose(out);
  214.                success = TRUE;
  215.             }
  216.             else ER_NewError(GetStr(MSG_ER_CantCreateFile), filename, NULL);
  217.          }
  218.          else ER_NewError(GetStr(MSG_ER_DocNotFound), path, NULL);
  219.       }
  220.       else ER_NewError(GetStr(MSG_ER_SendHTTP), NULL, NULL);
  221.       TR_Disconnect();
  222.    }
  223.    else ER_NewError(GetStr(MSG_ER_ConnectHTTP), host, NULL);
  224.    return success;
  225. }
  226. ///
  227.  
  228. /*** POP3 routines ***/
  229. /// TR_SendPopCmd
  230. //  Sends a command to the POP3 server
  231. BOOL TR_SendPopCmd(char *buf, char *cmdtext, char *parmtext, int flags)
  232. {
  233.    char cmdbuf[SIZE_COMMAND];
  234.    int len, ln;
  235.  
  236.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  237.    if (!parmtext || !*parmtext) sprintf(cmdbuf, "%s\r\n", cmdtext);
  238.    else sprintf(cmdbuf, "%s %s\r\n", cmdtext, parmtext);
  239.    if (!TR_SendDat(cmdbuf)) return FALSE;
  240.    if (!(len = TR_RecvDat(buf))) return FALSE;
  241.    if (flags & POPCMD_WAITEOL)
  242.       while (buf[len-1] != '\n') if (ln = TR_RecvDat(&buf[len])) len += ln; else return FALSE;
  243.    if (!strncmp(buf, "-ERR", 4))
  244.    {
  245.       if (!(flags & POPCMD_NOERROR)) ER_NewError(GetStr(MSG_ER_BadResponse), cmdtext, buf);
  246.       return FALSE;
  247.    }
  248.    return TRUE;
  249. }
  250. ///
  251. /// TR_ConnectPOP
  252. //  Connects to a POP3 mail server
  253. int TR_ConnectPOP(int guilevel)
  254. {     
  255.    char passwd[SIZE_PASSWORD], host[SIZE_HOST], buf[SIZE_LINE], *p;
  256.    int err, pop = G->TR->POP_Nr, msgs, port = 110;
  257.  
  258.    strcpy(passwd, C->P3[pop]->Password);
  259.    strcpy(host, C->P3[pop]->Server);
  260.    if (C->TransferWindow == 2 || (C->TransferWindow == 1 && (guilevel == POP_START || guilevel == POP_USER))) set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);
  261.    set(G->TR->GUI.TX_STATUS  , MUIA_Text_Contents,GetStr(MSG_TR_Connecting));
  262.    if (p = strchr(host, ':')) { *p = 0; port = atoi(++p); }
  263.    TR_SetWinTitle(TRUE, host);
  264.    if (err = TR_Connect(host, port))
  265.    {
  266.       if (guilevel == POP_USER) switch (err)
  267.       {
  268.          case -1: ER_NewError(GetStr(MSG_ER_UnknownPOP), C->P3[pop]->Server, NULL); break;
  269.          default: ER_NewError(GetStr(MSG_ER_CantConnect), C->P3[pop]->Server, NULL);
  270.       }
  271.       return -1;
  272.    }
  273.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_WaitWelcome));
  274.    if (!TR_RecvDat(buf)) return -1;
  275.    if (!*passwd)
  276.    {
  277.       sprintf(buf, GetStr(MSG_TR_PopLoginReq), C->P3[pop]->User, host);
  278.       if (!StringRequest(passwd, SIZE_PASSWORD, GetStr(MSG_TR_PopLogin), buf, GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), TRUE, G->TR->GUI.WI)) return -1;
  279.    }
  280.    if (C->P3[pop]->UseAPOP)
  281.    {
  282.       MD5_CTX context;
  283.       UBYTE digest[16], *welcomemsg = StrBufCpy(NULL, buf);
  284.       int i, j;
  285.  
  286.       while (!strstr(buf, "\n"))
  287.       {
  288.          if (!TR_RecvDat(buf)) return -1;
  289.          welcomemsg = StrBufCat(welcomemsg, buf);
  290.       }
  291.       *buf = 0;
  292.       if (p = strchr(welcomemsg, '<'))
  293.       {
  294.          strcpy(buf, p);
  295.          if (p = strchr(buf, '>')) p[1] = 0;
  296.       }
  297.       else ER_NewError(GetStr(MSG_ER_NoAPOP), NULL, NULL);
  298.       strcat(buf, passwd);
  299.       FreeStrBuf(welcomemsg);
  300.       MD5Init(&context);
  301.       MD5Update(&context, buf, strlen(buf));
  302.       MD5Final(digest, &context);
  303.       sprintf(buf, "%s ", C->P3[pop]->User);
  304.       for (j=strlen(buf), i=0; i<16; j+=2, i++) sprintf(&buf[j], "%02x", digest[i]);
  305.       buf[j] = 0;
  306.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendAPOPLogin));
  307.       if (!TR_SendPopCmd(buf, "APOP", buf, POPCMD_WAITEOL)) return -1;
  308.    }
  309.    else
  310.    {
  311.       while (!strstr(buf, "\n")) if (!TR_RecvDat(buf)) return -1;
  312.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendUserID));
  313.       if (!TR_SendPopCmd(buf, "USER", C->P3[pop]->User, POPCMD_WAITEOL)) return -1;
  314.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendPassword));
  315.       if (!TR_SendPopCmd(buf, "PASS", passwd, POPCMD_WAITEOL)) return -1;
  316.    }
  317.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_GetStats));
  318.    if (!TR_SendPopCmd(buf, "STAT", NULL, POPCMD_WAITEOL)) return -1;
  319.    sscanf(&buf[4], "%ld", &msgs);
  320.    if (msgs) AppendLogVerbose(31, GetStr(MSG_LOG_ConnectPOP), C->P3[pop]->User, host, (void *)msgs, "");
  321.    return msgs;
  322. }
  323. ///
  324. /// TR_DisplayMailList
  325. //  Displays a list of messages ready for download
  326. void TR_DisplayMailList(BOOL largeonly)
  327. {
  328.    struct Mail *mail;
  329.    APTR lv = G->TR->GUI.LV_MAILS;
  330.    int pos = 0;
  331.    set(lv, MUIA_NList_Quiet, TRUE);
  332.    for (mail = G->TR->List; mail; mail = mail->Next)
  333.       if (mail->Size >= C->WarnSize<<10 || !largeonly)
  334.       {
  335.          mail->Position = pos++;
  336.          DoMethod(lv, MUIM_NList_InsertSingle, mail, MUIV_NList_Insert_Bottom);
  337.       }
  338.    set(lv, MUIA_NList_Quiet, FALSE);
  339. }
  340. ///
  341. /// TR_AddMessageHeader
  342. //  Parses downloaded message header
  343. void TR_AddMessageHeader(int *count, int size, char *tfname)
  344. {
  345.    struct Mail *mail;
  346.    struct ExtendedMail *email;
  347.  
  348.    if (email = MA_ExamineMail((struct Folder *)-1, tfname, NULL, FALSE))
  349.    {
  350.       mail = calloc(1,sizeof(struct Mail));
  351.       *mail = email->Mail;
  352.       mail->Folder  = NULL;
  353.       mail->Status  = 1;
  354.       mail->Index   = ++(*count);
  355.       mail->Size    = size;
  356.       MA_FreeEMailStruct(email);
  357.       MyAddTail(&(G->TR->List), mail);
  358.    }
  359. }
  360. ///
  361. /// TR_GetMessageList_IMPORT
  362. //  Collects messages from a UUCP mailbox file
  363. void TR_GetMessageList_IMPORT(FILE *fh)
  364. {
  365.    BOOL body = FALSE;
  366.    int c = 0, size = 0;
  367.    char buffer[SIZE_LINE], *ptr, *tfname = "yamIMP.tmp", fname[SIZE_PATHFILE];
  368.    FILE *f = NULL;
  369.  
  370.    strmfp(fname, C->TempDir, tfname);
  371.    G->TR->List = NULL;
  372.    fseek(fh, 0, SEEK_SET);
  373.    while (fgets(buffer, SIZE_LINE, fh))
  374.    {
  375.       if (f || body) size += strlen(buffer);
  376.       if (ptr = strpbrk(buffer, "\r\n")) *ptr = 0;
  377.       if (!f && !strncmp(buffer, "From ", 5))
  378.       {
  379.          if (body) { TR_AddMessageHeader(&c, size, tfname); DeleteFile(fname); }
  380.          if (!(f = fopen(fname, "w"))) break;
  381.          size = 0; body = FALSE;
  382.       }
  383.       if (f)
  384.       {
  385.          fputs(buffer, f); fputc('\n', f);
  386.          if (!*buffer)
  387.          { 
  388.             fclose(f); f = NULL;
  389.             body = TRUE;
  390.          }
  391.       }
  392.    }
  393.    if (body) { TR_AddMessageHeader(&c, size, tfname); DeleteFile(fname); }
  394.    TR_DisplayMailList(FALSE);
  395. }
  396. ///
  397. /// TR_GetMessageList_GET
  398. //  Collects messages waiting on a POP3 server
  399. BOOL TR_GetMessageList_GET(int maxmsgs)
  400. {
  401.    char buf[SIZE_LINE];
  402.  
  403.    if (TR_SendPopCmd(buf, "LIST", NULL, 0))
  404.    {
  405.       int mode, l = 0, index, size;
  406.       char line[SIZE_DEFAULT], *bufptr;
  407.       BOOL done = FALSE;
  408.       struct Mail *new;
  409.  
  410.       G->TR->List = NULL;
  411.       if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  412.       else if (TR_RecvDat(buf) > 0) if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  413.       if (!bufptr) return FALSE;
  414.       while (!G->Error)
  415.       {
  416.          for (; *bufptr; bufptr++)
  417.          {
  418.             if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  419.             if (*bufptr != '\n') continue;
  420.             line[l] = 0; l = 0;
  421.             if (line[0] == '.' && line[1] == '\n') { done = TRUE; break; }
  422.             sscanf(line, "%ld %ld", &index, &size);
  423.             if (index) if (new = calloc(1,sizeof(struct Mail)))
  424.             {
  425.                static int mode2status[16] = { 1,1,3,3,1,1,3,3,0,1,0,3,0,1,0,3 };
  426.                new->Index = index; new->Size = size; new->Folder = NULL;
  427.                mode = (C->DownloadLarge ? 1 : 0) +
  428.                       (C->P3[G->TR->POP_Nr]->DeleteOnServer ? 2 : 0) +
  429.                       (G->TR->GUIlevel == POP_USER ? 4 : 0) +
  430.                       ((C->WarnSize && new->Size >= (C->WarnSize<<10)) ? 8 : 0);
  431.                new->Status = mode2status[mode];
  432.                MyAddTail(&(G->TR->List), new);
  433.             }
  434.          }
  435.          if (done) break;
  436.          if (TR_RecvDat(buf) <= 0) break;
  437.          bufptr = buf;
  438.       }
  439.       return TRUE;
  440.    }
  441.    else return FALSE;
  442. }
  443. ///
  444. /// TR_AppendUIDL
  445. //  Appends a UIDL to the .uidl file
  446. void TR_AppendUIDL(char *uidl)
  447. {
  448.    FILE *fh;
  449.    if (fh = fopen(CreateFilename(".uidl"), "a"))
  450.    {
  451.       fprintf(fh, "%s\n", uidl);
  452.       fclose(fh);
  453.    }
  454. }
  455. ///
  456. /// TR_FindUIDL
  457. //  Searches UIDL list for a given UIDL
  458. BOOL TR_FindUIDL(char *uidl)
  459. {
  460.    int l = strlen(uidl);
  461.    char *p = G->TR->UIDLloc;
  462.    if (p) while (*p)
  463.    {
  464.       if (!strncmp(p, uidl, l)) return TRUE;
  465.       while (*p) if (*p++ == '\n') break;
  466.    }
  467.    return FALSE;
  468. }
  469. ///
  470. /// TR_GetUIDLonDisk
  471. //  Loads local UIDL list from disk
  472. char *TR_GetUIDLonDisk(void)
  473. {
  474.    FILE *fh;
  475.    char *text = NULL, *file = CreateFilename(".uidl");
  476.    int size;
  477.  
  478.    if ((size = FileSize(file)) > 0)
  479.       if (text = calloc(size+1,1))
  480.          if (fh = fopen(file, "r"))
  481.          {
  482.             fread(text, 1, size, fh);
  483.             fclose(fh);
  484.          }
  485.    return text;
  486. }
  487. ///
  488. /// TR_GetUIDLonServer
  489. //  Gets remote UIDL list from the POP3 server
  490. BOOL TR_GetUIDLonServer(void)
  491. {
  492.    char buf[SIZE_LINE];
  493.  
  494.    if (TR_SendPopCmd(buf, "UIDL", NULL, POPCMD_NOERROR))
  495.    {
  496.       int num, l = 0;
  497.       struct Mail *mail;
  498.       char  uidl[SIZE_DEFAULT+SIZE_HOST], line[SIZE_DEFAULT], *bufptr;
  499.       BOOL done = FALSE;
  500.  
  501.       if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  502.       while (!G->Error)
  503.       {
  504.          for (; *bufptr; bufptr++)
  505.          {
  506.             if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  507.             if (*bufptr != '\n') continue;
  508.             line[l] = 0; l = 0;
  509.             if (line[0] == '.' && line[1] == '\n') { done = TRUE; break; }
  510.             sscanf(line, "%ld %s", &num, uidl);
  511.             strcat(uidl, "@"); strcat(uidl, C->P3[G->TR->POP_Nr]->Server);
  512.             for (mail = G->TR->List; mail; mail = mail->Next)
  513.                if (mail->Index == num) { mail->UIDL = AllocCopy(uidl, strlen(uidl)+1); break; }
  514.          }
  515.          if (done) break;
  516.          if (TR_RecvDat(buf) <= 0) break;
  517.          bufptr = buf;
  518.       }
  519.       return TRUE;
  520.    }
  521.    else return FALSE;
  522. }
  523. ///
  524. /// TR_ApplyRemoteFilters
  525. //  Applies remote filters to a message
  526. void TR_ApplyRemoteFilters(struct Mail *mail)
  527. {
  528.    int i;
  529.  
  530.    for (i = 0; i < G->TR->Scnt; i++) if (FI_DoComplexSearch(G->TR->Search[i], G->TR->Search[i]->Rule->Combine, G->TR->Search[i+MAXRU], mail))
  531.    {
  532.       struct Rule *rule = G->TR->Search[i]->Rule;
  533.       if (rule->Actions &   8) if (*rule->ExecuteCmd) ExecuteCommand(rule->ExecuteCmd, FALSE, NULL);
  534.       if (rule->Actions &  16) if (*rule->PlaySound) PlaySound(rule->PlaySound);
  535.       if (rule->Actions &  64) mail->Status |= 2; else mail->Status &= ~2;
  536.       if (rule->Actions & 128) mail->Status &= ~1; else mail->Status |= 1;
  537.       return;
  538.    }
  539. }
  540. ///
  541. /// TR_GetMessageDetails
  542. //  Gets header from a message stored on the POP3 server
  543. void TR_GetMessageDetails(struct Mail *mail, int lline)
  544. {
  545.    if (!*mail->From.Address)
  546.    {
  547.       char buf[SIZE_LINE], cmdbuf[SIZE_SMALL], *tfname = "yamTOP.tmp";
  548.       sprintf(cmdbuf, "%ld 1", mail->Index);
  549.       if (TR_SendPopCmd(buf, "TOP", cmdbuf, POPCMD_NOERROR))
  550.       {
  551.          char fname[SIZE_PATHFILE];
  552.          FILE *f;
  553.          strmfp(fname, C->TempDir, tfname);
  554.          if (f = fopen(fname, "w"))
  555.          {
  556.             struct ExtendedMail *email;
  557.             int l = 0;
  558.             char line[SIZE_LINE], *bufptr;
  559.             BOOL done = FALSE;
  560.  
  561.             if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  562.             while (!G->Error && !G->TR->Abort)
  563.             {
  564.                for (; *bufptr; bufptr++)
  565.                {
  566.                   if (*bufptr != '\r') line[l++] = *bufptr;
  567.                   if (l == SIZE_LINE-1)
  568.                   {
  569.                      line[l] = 0; l = 0;
  570.                      if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL); break; }
  571.                   }
  572.                   if (*bufptr != '\n') continue;
  573.                   line[l] = 0; l = 0;
  574.                   if (line[0] == '.') if (line[1] == '\n') { done = TRUE; break; }
  575.                   if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL); break; }
  576.                }
  577.                if (done) break;
  578.                if (TR_RecvDat(buf) <= 0) break;
  579.                bufptr = buf;
  580.             }
  581.             fclose(f);
  582.             if (email = MA_ExamineMail(NULL, tfname, NULL, TRUE))
  583.             {
  584.                mail->From    = email->Mail.From;
  585.                mail->To      = email->Mail.To;
  586.                mail->ReplyTo = email->Mail.ReplyTo;
  587.                strcpy(mail->Subject, email->Mail.Subject);
  588.                strcpy(mail->MailFile, email->Mail.MailFile);
  589.                mail->Date = email->Mail.Date;
  590.                if (lline == -1)
  591.                {
  592.                   char uidl[SIZE_DEFAULT+SIZE_HOST];
  593.                   sprintf(uidl, "%s@%s", Trim(email->MsgID), C->P3[G->TR->POP_Nr]->Server);
  594.                   mail->UIDL = AllocCopy(uidl, strlen(uidl)+1);
  595.                }
  596.                if (lline == -2) TR_ApplyRemoteFilters(mail);
  597.                DeleteFile(fname);
  598.                MA_FreeEMailStruct(email);
  599.             }
  600.          }
  601.          else ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL);
  602.          fclose(f);
  603.       }
  604.    }
  605.    if (lline >= 0) DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Redraw, lline);
  606. }
  607. ///
  608. /// TR_GetUIDL
  609. //  Filters out duplicate messages
  610. void TR_GetUIDL(void)
  611. {
  612.    struct Mail *mail;
  613.    G->TR->supportUIDL = TR_GetUIDLonServer();
  614.    G->TR->UIDLloc = TR_GetUIDLonDisk();
  615.    for (mail = G->TR->List; mail; mail = mail->Next)
  616.    {
  617.       if (!G->TR->supportUIDL) TR_GetMessageDetails(mail, -1);
  618.       if (TR_FindUIDL(mail->UIDL)) { G->TR->Stats.DupSkipped++; mail->Status &= 2; }
  619.    }
  620. }
  621. ///
  622. /// TR_DisconnectPOP
  623. //  Terminates a POP3 session
  624. void TR_DisconnectPOP(void)
  625. {
  626.    char buf[SIZE_LINE];
  627.  
  628.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_Disconnecting));
  629.    if (!G->TR->Abort) TR_SendPopCmd(buf, "QUIT", NULL, POPCMD_WAITEOL);
  630.    TR_Disconnect();
  631. }
  632. ///
  633. /// TR_GetMailFromNextPOP
  634. //  Downloads and filters mail from a POP3 account
  635. void TR_GetMailFromNextPOP(BOOL isfirst, int singlepop, int guilevel)
  636. {
  637.    extern SAVEDS void TR_ProcessGETFunc(void);
  638.    struct Mail *mail;
  639.    static int laststats;
  640.    int msgs, pop = singlepop;
  641.  
  642.    if (isfirst) /* Init first connection */
  643.    {
  644.       G->LastDL.Error = TRUE;
  645.       if (!TR_OpenTCPIP()) { if (guilevel == POP_USER) ER_NewError(GetStr(MSG_ER_NoTCP), NULL, NULL); return; }
  646.       if (!CO_IsValid()) { TR_CloseTCPIP(); return; }
  647.       if (!(G->TR = TR_New(TR_GET))) { TR_CloseTCPIP(); return; }
  648.       G->TR->Checking = TRUE; DisplayStatistics((struct Folder *)-1);
  649.       G->TR->GUIlevel = guilevel;
  650.       G->TR->Scnt = MA_AllocRules(G->TR->Search, APPLY_REMOTE);
  651.       if (singlepop >= 0) G->TR->SinglePOP = TRUE;
  652.       else G->TR->POP_Nr = -1;
  653.       laststats = 0;
  654.    }
  655.    else /* Finish previous connection */
  656.    {
  657.       struct POP3 *p = C->P3[G->TR->POP_Nr];
  658.       TR_DisconnectPOP();
  659.       TR_Cleanup();
  660.       AppendLogNormal(30, GetStr(MSG_LOG_Retrieving), (void *)(G->TR->Stats.Downloaded-laststats), p->User, p->Server, "");
  661.       if (G->TR->SinglePOP) pop = MAXP3;
  662.       laststats = G->TR->Stats.Downloaded;
  663.    }
  664.    if (!G->TR->SinglePOP) for (pop = ++G->TR->POP_Nr; pop < MAXP3; pop++)
  665.                              if (C->P3[pop]) if (C->P3[pop]->Enabled) break;
  666.    if (pop == MAXP3) /* Finish last connection */
  667.    {
  668.       TR_CloseTCPIP();
  669.       set(G->TR->GUI.WI, MUIA_Window_Open, FALSE);
  670.       MA_FreeRules(G->TR->Search, G->TR->Scnt);
  671.       MA_StartMacro(MACRO_POSTGET, itoa(G->TR->Stats.Downloaded));
  672.       DoMethod(G->App, MUIM_CallHook, &MA_ApplyRulesHook, APPLY_AUTO, 0, FALSE);
  673.       G->TR->Checking = FALSE; DisplayStatistics((struct Folder *)-1);
  674.       TR_NewMailAlert();
  675.       MA_ChangeTransfer(TRUE);
  676.       DisposeModulePush(&G->TR);
  677.       if (G->TR_Exchange)
  678.       {
  679.          G->TR_Exchange = FALSE;
  680.          DoMethod(G->App, MUIM_Application_PushMethod, G->App, 3, MUIM_CallHook, &MA_SendHook, SEND_ALL);
  681.       }
  682.       return;
  683.    }
  684.    G->TR->POP_Nr = pop;
  685.    G->TR_Allow = G->TR->Abort = G->Error = FALSE;
  686.    if ((msgs = TR_ConnectPOP(G->TR->GUIlevel)) != -1)
  687.    {
  688.       if (msgs)
  689.       {
  690.          if (TR_GetMessageList_GET(msgs))
  691.          {
  692.             BOOL preselect = FALSE;
  693.             G->TR->Stats.OnServer += msgs;
  694.             if (G->TR->Scnt)
  695.             {
  696.                set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_ApplyFilters));
  697.                for (mail = G->TR->List; mail; mail = mail->Next)
  698.                   TR_GetMessageDetails(mail, -2);
  699.             }
  700.             if (C->AvoidDuplicates) TR_GetUIDL();
  701.             if (G->TR->GUIlevel == POP_USER)
  702.             {
  703.                if (C->PreSelection >= 2) preselect = TRUE;
  704.                if (C->WarnSize && C->PreSelection)
  705.                   for (mail = G->TR->List; mail; mail = mail->Next)
  706.                      if (mail->Size >= C->WarnSize<<10) { preselect = TRUE; break; }
  707.             }
  708.             if (preselect)
  709.             {
  710.                set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);
  711.                if (C->PreSelection == 1)
  712.                {
  713.                   TR_DisplayMailList(TRUE);
  714.                   set(G->TR->GUI.GR_LIST, MUIA_ShowMe, TRUE);
  715.                   set(G->TR->GUI.WI, MUIA_Window_Activate, TRUE);
  716.                   DoMethod(G->TR->GUI.WI, MUIM_Window_ScreenToFront);
  717.                }
  718.                else TR_DisplayMailList(FALSE);
  719.                set(G->TR->GUI.GR_PAGE, MUIA_Group_ActivePage, 0);
  720.                G->TR->GMD_Mail = G->TR->List;
  721.                G->TR->GMD_Line = 0;
  722.                TR_CompleteMsgList();
  723.                return;
  724.             }
  725.             else
  726.             {
  727.                TR_ProcessGETFunc();
  728.             }
  729.             return;
  730.          }
  731.       }
  732.    }
  733.    else G->TR->Stats.Error = TRUE;
  734.    TR_GetMailFromNextPOP(FALSE, 0, 0);
  735. }
  736. ///
  737.  
  738. /*** SMTP routines ***/
  739. /// TR_SendSMTPCmd
  740. //  Sends a command to the SMTP server
  741. BOOL TR_SendSMTPCmd(char *cmdtext, char *parmtext)
  742. {
  743.    int len;
  744.    static char buffer[SIZE_LINE];
  745.    char cont;
  746.  
  747.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  748.    if (cmdtext) 
  749.    {
  750.       sprintf(buffer, "%s\r\n", cmdtext);
  751.       if (parmtext) if (*parmtext) sprintf(buffer, "%s %s\r\n", cmdtext, parmtext);
  752.    }
  753.    else *buffer = 0;
  754.    if (!TR_SendDat(buffer)) return FALSE;
  755.    if (!(len = TR_RecvDat(buffer))) return FALSE;
  756.    switch (atoi(buffer))
  757.    {
  758.       case 211: case 214: case 220: case 221: 
  759.       case 250: case 251: case 354: break;
  760.       default:  ER_NewError(GetStr(MSG_ER_BadResponse), cmdtext, buffer); return FALSE;
  761.    }
  762.    cont = buffer[3];
  763.    while (buffer[len-1] != '\n') if (!(len = TR_RecvDat(buffer))) return FALSE;
  764.    if (cont == '-') while (buffer[len-1] != '\n') if (!(len = TR_RecvDat(buffer))) break;
  765.    return TRUE;
  766. }
  767. ///
  768. /// TR_ConnectSMTP
  769. //  Connects to a SMTP mail server
  770. BOOL TR_ConnectSMTP(void)
  771. {
  772.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_WaitWelcome));
  773.    if (!TR_SendSMTPCmd(NULL, NULL)) return FALSE;
  774.    set(G->TR->GUI.TX_STATUS,MUIA_Text_Contents, GetStr(MSG_TR_SendHello));
  775.    if (!TR_SendSMTPCmd("HELO", C->SMTP_Domain)) return FALSE;
  776.    return TRUE;
  777. }
  778. ///
  779. /// TR_DisconnectSMTP
  780. //  Terminates a SMTP session
  781. void TR_DisconnectSMTP(void)
  782. {
  783.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_Disconnecting));
  784.    if (!G->TR->Abort) TR_SendSMTPCmd("QUIT", NULL);
  785.    TR_Disconnect();
  786. }
  787. ///
  788. /// TR_ChangeStatusFunc
  789. //  Changes status of selected messages
  790. SAVEDS ASM void TR_ChangeStatusFunc(REG(a1) int *arg)
  791. {
  792.    int id = MUIV_NList_NextSelected_Start;
  793.    struct Mail *mail;
  794.    for (;;)
  795.    {
  796.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_NextSelected, &id);
  797.       if (id == MUIV_NList_NextSelected_End) break;
  798.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_GetEntry, id, &mail);
  799.       mail->Status = *arg;
  800.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Redraw, id);
  801.    }
  802. }
  803. MakeHook(TR_ChangeStatusHook, TR_ChangeStatusFunc);
  804. ///
  805. /// TR_GetSeconds
  806. //  Gets current date and time in seconds
  807. long TR_GetSeconds(void)
  808. {
  809.    struct DateStamp ds;
  810.    DateStamp(&ds);
  811.    return ((86400*ds.ds_Days) + (60*ds.ds_Minute) + (ds.ds_Tick/50));
  812. }
  813. ///
  814. /// TR_TransStat_Init
  815. //  Initializes transfer statistics
  816. void TR_TransStat_Init(struct TransStat *ts)
  817. {
  818.    struct Mail *mail;
  819.  
  820.    ts->Msgs_Tot = ts->Size_Tot = 0;
  821.    if (G->TR->GUI.GR_LIST)
  822.    {
  823.       set(G->TR->GUI.GR_PAGE, MUIA_Group_ActivePage, 1);
  824.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);
  825.    }
  826.    for (mail = G->TR->List; mail; mail = mail->Next)
  827.    {
  828.       ts->Msgs_Tot++;
  829.       if (mail->Status & 1) ts->Size_Tot += mail->Size;
  830.    }
  831. }
  832. ///
  833. /// TR_TransStat_Start
  834. //  Resets statistics display
  835. void TR_TransStat_Start(struct TransStat *ts)
  836. {
  837.    ts->Msgs_Done = ts->Size_Done = 0;
  838.    sprintf(G->TR->CountLabel, GetStr(MSG_TR_MessageGauge), "%ld", ts->Msgs_Tot);
  839.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_InfoText, G->TR->CountLabel);
  840.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_Max, ts->Msgs_Tot);
  841.    ts->Clock_Start = TR_GetSeconds();
  842. }
  843. ///
  844. /// TR_TransStat_NextMsg
  845. //  Updates statistics display for next message
  846. void TR_TransStat_NextMsg(struct TransStat *ts, int index, int listpos, int size, char *status)
  847. {
  848.    ts->Size_Curr = 0;
  849.    ts->Clock_Last = 0;
  850.    ts->Delay = 0;
  851.    if (!GetMUI(G->TR->GUI.WI, MUIA_Window_Open)) return;
  852.    else if (size <    2500) ts->Delay = 256;
  853.    else if (size <   25000) ts->Delay = 512;
  854.    else if (size <  250000) ts->Delay = 1024;
  855.    else if (size < 2500000) ts->Delay = 2048;
  856.    else                     ts->Delay = 4096;
  857.    if (G->TR->GUI.GR_LIST && listpos >= 0) set(G->TR->GUI.LV_MAILS, MUIA_NList_Active, listpos);
  858.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, status);
  859.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_Current, index);
  860.    sprintf(G->TR->BytesLabel, GetStr(MSG_TR_SizeGauge), size);
  861.    set(G->TR->GUI.GA_BYTES, MUIA_Gauge_InfoText, G->TR->BytesLabel);
  862.    set(G->TR->GUI.GA_BYTES, MUIA_Gauge_Max, size);
  863. }
  864. ///
  865. /// TR_TransStat_Update
  866. //  Updates statistics display for next block of data
  867. void TR_TransStat_Update(struct TransStat *ts, int size_incr)
  868. {
  869.    long clock;
  870.    int speed = 0, remclock = 0;
  871.    static long size_done = 0;
  872.  
  873.    if (!ts->Size_Done) size_done = 0;
  874.    ts->Size_Curr += size_incr;
  875.    ts->Size_Done += size_incr;
  876.    if (!ts->Delay) return;
  877.    if (ts->Size_Done-size_done > ts->Delay)
  878.    {
  879.       set(G->TR->GUI.GA_BYTES, MUIA_Gauge_Current, ts->Size_Curr);
  880.       DoMethod(G->App, MUIM_Application_InputBuffered);
  881.       size_done = ts->Size_Done;
  882.    }
  883.    if ((clock = (TR_GetSeconds()-ts->Clock_Start)) == ts->Clock_Last) return;
  884.    ts->Clock_Last = clock;
  885.    if (clock) speed = ts->Size_Done/clock;
  886.    if (speed) remclock = MAX(ts->Size_Tot/speed-clock,0);
  887.    sprintf(G->TR->StatsLabel, GetStr(MSG_TR_TransferStats),
  888.       ts->Size_Done>>10, ts->Size_Tot>>10, speed, remclock/60, remclock%60);
  889.    set(G->TR->GUI.TX_STATS, MUIA_Text_Contents, G->TR->StatsLabel);
  890. }
  891. ///
  892. /// TR_Cleanup
  893. //  Free temporary message and UIDL lists
  894. void TR_Cleanup(void)
  895. {
  896.    struct Mail *work, *next;
  897.  
  898.    if (G->TR->GUI.LV_MAILS) DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Clear);
  899.    for (work = G->TR->List; work; work = next)
  900.    {
  901.       next = work->Next;
  902.       if (work->UIDL) free(work->UIDL);
  903.       free(work);
  904.    }
  905.    if (G->TR->UIDLloc) free(G->TR->UIDLloc);
  906.    G->TR->UIDLloc = NULL;
  907.    G->TR->List = NULL;
  908. }
  909. ///
  910. /// TR_AbortnClose
  911. //  Aborts a transfer
  912. void TR_AbortnClose(void)
  913. {
  914.    set(G->TR->GUI.WI, MUIA_Window_Open, FALSE);
  915.    TR_Cleanup();
  916.    MA_ChangeTransfer(TRUE);
  917.    DisposeModulePush(&G->TR);
  918. }
  919. ///
  920. /// TR_ApplySentFilters
  921. //  Applies filters to a sent message
  922. BOOL TR_ApplySentFilters(struct Mail *mail)
  923. {
  924.    int i;
  925.    for (i = 0; i < G->TR->Scnt; i++)
  926.       if (FI_DoComplexSearch(G->TR->Search[i], G->TR->Search[i]->Rule->Combine, G->TR->Search[i+MAXRU], mail))
  927.          if (!MA_ExecuteRuleAction(G->TR->Search[i]->Rule, mail)) return FALSE;
  928.    return TRUE;
  929. }
  930. ///
  931.  
  932. /*** EXPORT ***/
  933. /// TR_ProcessEXPORT
  934. //  Saves a list of messages to a UUCP mailbox file
  935. BOOL TR_ProcessEXPORT(char *fname, struct Mail **mlist, BOOL append)
  936. {
  937.    BOOL success = FALSE;
  938.    struct TransStat ts;
  939.    int i, c;
  940.    char buf[SIZE_LINE], fullfile[SIZE_PATHFILE];
  941.    FILE *fh, *mfh;
  942.    struct Mail *mail, *new;
  943.  
  944.    G->TR->List = NULL;
  945.    for (c = i = 0; i < (int)*mlist; i++)
  946.    {
  947.       if (new = calloc(1,sizeof(struct Mail)))
  948.       {
  949.          *new = *mlist[i+2];
  950.          new->Index = ++c; new->Status = 1;
  951.          MyAddTail(&(G->TR->List), new);
  952.       }
  953.    }
  954.    if (c)
  955.    {
  956.       TR_SetWinTitle(FALSE, FilePart(fname));
  957.       TR_TransStat_Init(&ts);
  958.       TR_TransStat_Start(&ts);
  959.       if (fh = fopen(fname, append ? "a" : "w"))
  960.       {
  961.          success = TRUE;
  962.          for (mail = G->TR->List; mail && !G->TR->Abort; mail = mail->Next)
  963.          {
  964.             ts.Msgs_Done++;
  965.             TR_TransStat_NextMsg(&ts, mail->Index, -1, mail->Size, GetStr(MSG_TR_Exporting));
  966.             if (StartUnpack(GetMailFile(NULL, NULL, mail), fullfile, mail->Folder))
  967.             {
  968.                if (mfh = fopen(fullfile, "r"))
  969.                {
  970.                   fprintf(fh, "From %s %s", mail->From.Address, DateStamp2String(&mail->Date, DSS_UNIXDATE));
  971.                   while (fgets(buf, SIZE_LINE, mfh) && !G->TR->Abort)
  972.                   {
  973.                      if (!strncmp(buf, "From ", 5)) fputc('>', fh);
  974.                      fputs(buf, fh);
  975.                      TR_TransStat_Update(&ts, strlen(buf));
  976.                   }
  977.                   if (*buf) if (buf[strlen(buf)-1] != '\n') fputc('\n', fh);
  978.                   fclose(mfh);
  979.                }
  980.                FinishUnpack(fullfile);
  981.             }
  982.          }
  983.       }
  984.       fclose(fh);
  985.       AppendLog(51, GetStr(MSG_LOG_Exporting), (void *)ts.Msgs_Done, G->TR->List->Folder->Name, fname, "");
  986.    }
  987.    TR_AbortnClose();
  988.    return success;
  989. }
  990. ///
  991.  
  992. /*** SEND ***/
  993. /// TR_SendMessage
  994. //  Sends a single message
  995. int TR_SendMessage(struct TransStat *ts, struct Mail *mail)
  996. {
  997.    int result = 0;
  998.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  999.    char *mf;
  1000.    FILE *f;
  1001.  
  1002.    if (f = fopen(mf = GetMailFile(NULL, outfolder, mail), "r"))
  1003.    {
  1004.       char buf[SIZE_LINE];
  1005.       sprintf(buf, "FROM:<%s>", C->EmailAddress);
  1006.       if (TR_SendSMTPCmd("MAIL", buf))
  1007.       {
  1008.          int j;
  1009.          BOOL rcptok = TRUE;
  1010.          struct ExtendedMail *email = MA_ExamineMail(outfolder, mail->MailFile, NULL, TRUE);
  1011.          sprintf(buf, "TO:<%s>", mail->To.Address);
  1012.          if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1013.          for (j = 0; j < email->NoSTo && rcptok; j++)
  1014.          {
  1015.             sprintf(buf, "TO:<%s>", email->STo[j].Address);
  1016.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1017.          }
  1018.          for (j = 0; j < email->NoCC && rcptok; j++)
  1019.          {
  1020.             sprintf(buf, "TO:<%s>", email->CC[j].Address);
  1021.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1022.          }
  1023.          for (j = 0; j < email->NoBCC && rcptok; j++)
  1024.          {
  1025.             sprintf(buf, "TO:<%s>", email->BCC[j].Address);
  1026.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1027.          }
  1028.          if (rcptok)
  1029.          {
  1030.             if (TR_SendSMTPCmd("DATA", NULL)) 
  1031.             {
  1032.                BOOL infield = FALSE, inbody = FALSE;
  1033.                while (fgets(buf, SIZE_LINE-1, f) && !G->TR->Abort && !G->Error)
  1034.                {
  1035.                   char *p, sendbuf[SIZE_LINE+2];
  1036.                   int sb = strlen(buf);
  1037.                   if (p = strpbrk(buf, "\r\n")) *p = 0;
  1038.                   if (!*buf && !inbody)
  1039.                   {
  1040.                      inbody = TRUE; infield = FALSE;
  1041.                   }
  1042.                   if (!ISpace(*buf) && !inbody) infield = !strnicmp(buf, "bcc", 3) || !strnicmp(buf, "x-yam-", 6);
  1043.                   if (!infield)
  1044.                   {
  1045.                      *sendbuf = 0;
  1046.                      if (*buf == '.') strcat(sendbuf, "."); /* RFC 821 */
  1047.                      strcat(sendbuf, buf);
  1048.                      strcat(sendbuf, "\r\n");
  1049.                      if (!TR_SendDat(sendbuf)) ER_NewError(GetStr(MSG_ER_ConnectionBroken), NULL, NULL);
  1050.                   }
  1051.                   TR_TransStat_Update(ts, sb);
  1052.                }
  1053.                if (_OSERR) ER_NewError(GetStr(MSG_ER_ErrorReadMailfile), mf, NULL);
  1054.                else if (!G->TR->Abort && !G->Error)
  1055.                {
  1056.                   result = email->DelSend ? 2 : 1;
  1057.                   AppendLogVerbose(41, GetStr(MSG_LOG_SendingVerbose), AddrName(mail->To), mail->Subject, (void *)mail->Size, "");
  1058.                }
  1059.                TR_SendSMTPCmd("\r\n.", NULL);
  1060.             }
  1061.          }
  1062.          else ER_NewError(GetStr(MSG_ER_InvalidAddress), buf, NULL);
  1063.          MA_FreeEMailStruct(email);
  1064.       }
  1065.       fclose(f);
  1066.    }
  1067.    else ER_NewError(GetStr(MSG_ER_CantOpenFile), mf, NULL);
  1068.    return result;
  1069. }
  1070. ///
  1071. /// TR_ProcessSEND
  1072. //  Sends a list of messages
  1073. BOOL TR_ProcessSEND(struct Mail **mlist)
  1074. {
  1075.    struct TransStat ts;
  1076.    int c, i, port = 25, err;
  1077.    struct Mail *mail, *new;
  1078.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  1079.    struct Folder *sentfolder = FO_GetFolderByType(FT_SENT, NULL);
  1080.    BOOL success = FALSE;
  1081.    char *p;
  1082.  
  1083.    G->TR->List = NULL;
  1084.    G->TR_Allow = G->TR->Abort = G->Error = FALSE;
  1085.    for (c = i = 0; i < (int)*mlist; i++)
  1086.    {
  1087.       mail = mlist[i+2];
  1088.       if (mail->Status == STATUS_WFS || mail->Status == STATUS_ERR) if (new = malloc(sizeof(struct Mail)))
  1089.       {
  1090.          *new = *mail;
  1091.          new->Index = ++c;
  1092.          new->Status = 1;
  1093.          new->Reference = mail;
  1094.          new->Next = NULL;
  1095.          MyAddTail(&(G->TR->List), new);
  1096.       }
  1097.    }
  1098.    if (c)
  1099.    {
  1100.       char host[SIZE_HOST];
  1101.       G->TR->Scnt = MA_AllocRules(G->TR->Search, APPLY_SENT);
  1102.       TR_TransStat_Init(&ts);
  1103.       TR_TransStat_Start(&ts);
  1104.       strcpy(host, C->SMTP_Server);
  1105.       if (p = strchr(host, ':')) { *p = 0; port = atoi(++p); }
  1106.       TR_SetWinTitle(FALSE, host);
  1107.       if (!(err = TR_Connect(host, port)))
  1108.       {
  1109.          if (TR_ConnectSMTP())
  1110.          {
  1111.             success = TRUE;
  1112.             AppendLogVerbose(41, GetStr(MSG_LOG_ConnectSMTP), host, "", "", "");
  1113.             for (mail = G->TR->List; mail; mail = mail->Next)
  1114.             {
  1115.                if (G->TR->Abort || G->Error) break;
  1116.                ts.Msgs_Done++;
  1117.                TR_TransStat_NextMsg(&ts, mail->Index, -1, mail->Size, GetStr(MSG_TR_Sending));
  1118.                switch (TR_SendMessage(&ts, mail))
  1119.                {
  1120.                   case 0: MA_SetMailStatus(mail->Reference, STATUS_ERR);
  1121.                           TR_SendSMTPCmd("RSET", NULL);
  1122.                           break;
  1123.                   case 1: MA_SetMailStatus(mail->Reference, STATUS_SNT);
  1124.                           if (TR_ApplySentFilters(mail->Reference)) MA_MoveCopy(mail->Reference, outfolder, sentfolder, FALSE);
  1125.                           break;
  1126.                   case 2: MA_SetMailStatus(mail->Reference, STATUS_SNT);
  1127.                           if (TR_ApplySentFilters(mail->Reference)) MA_DeleteSingle(mail->Reference, FALSE);
  1128.                }
  1129.             }
  1130.             TR_DisconnectSMTP();
  1131.             AppendLogNormal(40, GetStr(MSG_LOG_Sending), (void *)c, host, "", "");
  1132.          }
  1133.       }
  1134.       else switch (err)
  1135.       {
  1136.          case -1: ER_NewError(GetStr(MSG_ER_UnknownSMTP), C->SMTP_Server, NULL); break;
  1137.          default: ER_NewError(GetStr(MSG_ER_CantConnect), C->SMTP_Server, NULL);
  1138.       }
  1139.       MA_FreeRules(G->TR->Search, G->TR->Scnt);
  1140.    }
  1141.    TR_AbortnClose();
  1142.    return success;
  1143. }
  1144. ///
  1145.  
  1146. /*** IMPORT ***/
  1147. /// TR_AbortIMPORTFunc
  1148. //  Aborts import process
  1149. SAVEDS void TR_AbortIMPORTFunc(void)
  1150. {
  1151.    TR_AbortnClose();
  1152. }
  1153. MakeHook(TR_AbortIMPORTHook, TR_AbortIMPORTFunc);
  1154. ///
  1155. /// TR_ProcessIMPORTFunc
  1156. //  Imports messages from a UUCP mailbox file
  1157. SAVEDS void TR_ProcessIMPORTFunc(void)
  1158. {
  1159.    struct TransStat ts;
  1160.    FILE *fh, *f = NULL;
  1161.  
  1162.    TR_TransStat_Init(&ts);
  1163.    if (ts.Msgs_Tot)
  1164.    {
  1165.       TR_TransStat_Start(&ts);
  1166.       if (fh = fopen(G->TR->ImportFile, "r"))
  1167.       {
  1168.          struct ExtendedMail *email;
  1169.          struct Mail *mail = G->TR->List;
  1170.          static char mfile[SIZE_MFILE];
  1171.          BOOL header = FALSE, body = FALSE;
  1172.          struct Folder *folder = G->TR->ImportBox;
  1173.          int btype = folder->Type;
  1174.          char buffer[SIZE_LINE], *stat;
  1175.  
  1176.          if (btype == FT_OUTGOING) stat = Status[STATUS_WFS];
  1177.          else if (btype == FT_SENT || btype == FT_CUSTOMSENT) stat = Status[STATUS_SNT];
  1178.          else stat = " ";
  1179.          while (fgets(buffer, SIZE_LINE, fh) && !G->TR->Abort)
  1180.          {
  1181.             if (!header && !strncmp(buffer, "From ", 5))
  1182.             {
  1183.                if (body)
  1184.                {
  1185.                   if (f)
  1186.                   {
  1187.                      fclose(f); f = NULL;
  1188.                      if (email = MA_ExamineMail(folder, mfile, stat, FALSE))
  1189.                      {
  1190.                         AddMailToList((struct Mail *)email, folder);
  1191.                         MA_FreeEMailStruct(email);
  1192.                      }
  1193.                   }
  1194.                   mail = mail->Next;
  1195.                }
  1196.                header = TRUE; body = FALSE;
  1197.                if (mail->Status & 1)
  1198.                {
  1199.                   ts.Msgs_Done++;
  1200.                   TR_TransStat_NextMsg(&ts, mail->Index, mail->Position, mail->Size, GetStr(MSG_TR_Importing));
  1201.                   f = fopen(MA_NewMailFile(folder, mfile, 0), "w");
  1202.                }
  1203.             } 
  1204.             else if (f && (header || body))
  1205.             { 
  1206.                fputs(buffer, f);
  1207.                TR_TransStat_Update(&ts, strlen(buffer));
  1208.             }
  1209.             if (header && !buffer[1]) { body = TRUE; header = FALSE; }
  1210.          }
  1211.          if (body && f)
  1212.          {
  1213.             fclose(f);
  1214.             if (email = MA_ExamineMail(folder, mfile, stat, FALSE))
  1215.             {
  1216.                AddMailToList((struct Mail *)email, folder);
  1217.                MA_FreeEMailStruct(email);
  1218.             }
  1219.          }
  1220.          fclose(fh);
  1221.          DisplayMailList(folder, G->MA->GUI.NL_MAILS);
  1222.          AppendLog(50, GetStr(MSG_LOG_Importing), (void *)ts.Msgs_Done, G->TR->ImportFile, folder->Name, "");
  1223.          DisplayStatistics(folder);
  1224.       }
  1225.    }
  1226.    TR_AbortnClose();
  1227. }
  1228. MakeHook(TR_ProcessIMPORTHook, TR_ProcessIMPORTFunc);
  1229. ///
  1230.  
  1231. /*** GET ***/
  1232. /// TR_AbortGETFunc
  1233. //  Aborts a POP3 download
  1234. SAVEDS void TR_AbortGETFunc(void)
  1235. {
  1236.    MA_FreeRules(G->TR->Search, G->TR->Scnt);
  1237.    TR_AbortnClose();
  1238.    TR_CloseTCPIP();
  1239.    G->TR->Checking = FALSE; DisplayStatistics((struct Folder *)-1);
  1240. }
  1241. MakeHook(TR_AbortGETHook, TR_AbortGETFunc);
  1242. ///
  1243. /// TR_LoadMessage
  1244. //  Retrieves a message from the POP3 server
  1245. BOOL TR_LoadMessage(struct TransStat *ts, int number)
  1246. {
  1247.    static char mfile[SIZE_MFILE];
  1248.    struct Folder *infolder = FO_GetFolderByType(FT_INCOMING, NULL);
  1249.    char msgnum[SIZE_SMALL], buf[SIZE_LINE], msgfile[SIZE_PATHFILE];
  1250.    FILE *f;
  1251.  
  1252.    stccpy(msgfile, MA_NewMailFile(infolder, mfile, 0), SIZE_PATHFILE);
  1253.    if (f = fopen(msgfile, "w"))
  1254.    {
  1255.       sprintf(msgnum, "%ld", number);
  1256.       if (TR_SendPopCmd(buf, "RETR", msgnum, 0))
  1257.       {
  1258.          int l = 0;
  1259.          char line[SIZE_LINE], *bufptr;
  1260.          BOOL done = FALSE;
  1261.  
  1262.          if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  1263.          while (!G->Error && !G->TR->Abort)
  1264.          {
  1265.             for (; *bufptr; bufptr++)
  1266.             {
  1267.                if (*bufptr != '\r') line[l++] = *bufptr;
  1268.                if (l == SIZE_LINE-1)
  1269.                {
  1270.                   TR_TransStat_Update(ts, l);
  1271.                   line[l] = 0; l = 0;
  1272.                   if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), mfile, NULL); break; }
  1273.                }
  1274.                if (*bufptr != '\n') continue;
  1275.                TR_TransStat_Update(ts, l+1);
  1276.                line[l] = 0; l = 0;
  1277.                if (line[0] == '.')
  1278.                   if (line[1] == '\n') { done = TRUE; break; }
  1279.                   else l = 1;  /* RFC 1725 */
  1280.                if (fputs(&line[l], f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), mfile, NULL); break; }
  1281.                l = 0;
  1282.             }
  1283.             if (done) break;
  1284.             if (TR_RecvDat(buf) <= 0) break;
  1285.             bufptr = buf;
  1286.          }
  1287.       }
  1288.       else ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), (char *)"", NULL);
  1289.       fclose(f);
  1290.       if (!G->TR->Abort && !G->Error)
  1291.       {
  1292.          struct ExtendedMail *mail;
  1293.          if (mail = MA_ExamineMail(infolder, mfile, " ", FALSE))
  1294.          {
  1295.             struct Mail *new = AddMailToList((struct Mail *)mail, infolder);
  1296.             if (FO_GetCurrentFolder() == infolder) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_InsertSingle, new, MUIV_NList_Insert_Sorted);
  1297.             AppendLogVerbose(32, GetStr(MSG_LOG_RetrievingVerbose), AddrName(new->From), new->Subject, (void *)new->Size, "");
  1298.             MA_StartMacro(MACRO_NEWMSG, mfile);
  1299.             MA_FreeEMailStruct(mail);
  1300.          }
  1301.          return TRUE;
  1302.       }
  1303.       DeleteFile(msgfile);
  1304.    }
  1305.    return FALSE;
  1306. }
  1307. ///
  1308. /// TR_DeleteMessage
  1309. //  Deletes a message on the POP3 server
  1310. void TR_DeleteMessage(int number)
  1311. {
  1312.    char msgnum[SIZE_SMALL], buf[SIZE_LINE];
  1313.  
  1314.    sprintf(msgnum, "%ld", number);
  1315.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_DeletingServerMail));
  1316.    if (TR_SendPopCmd(buf, "DELE", msgnum, POPCMD_WAITEOL)) G->TR->Stats.Deleted++;
  1317. }
  1318. ///
  1319. /// TR_NewMailAlert
  1320. //  Notifies user when new mail is available
  1321. void TR_NewMailAlert(void)
  1322. {
  1323.    struct DownloadResult *stats = &G->TR->Stats;
  1324.  
  1325.    memcpy(&G->LastDL, stats, sizeof(struct DownloadResult));
  1326.    if (!stats->Downloaded) return;
  1327.    if ((C->NotifyType & NOTI_REQ) && G->TR->GUIlevel != POP_REXX)
  1328.    {
  1329.       int iconified;
  1330.       static char buffer[SIZE_LARGE];
  1331.       struct RuleResult *rr = &G->RRs;
  1332.       get(G->App, MUIA_Application_Iconified, &iconified);
  1333.       if (iconified) { PopUp(); Delay(50L); }
  1334.       sprintf(buffer, GetStr(MSG_TR_NewMailReq),
  1335.          stats->Downloaded, stats->OnServer-stats->Deleted, stats->DupSkipped);
  1336.       sprintf(&buffer[strlen(buffer)], GetStr(MSG_TR_FilterStats),
  1337.          rr->Checked, rr->Bounced, rr->Forwarded, rr->Replied, rr->Executed, rr->Moved, rr->Deleted);
  1338.       InfoWindow(GetStr(MSG_TR_NewMail), buffer, GetStr(MSG_Okay), G->MA->GUI.WI);
  1339.    }
  1340.    if (C->NotifyType & NOTI_CMD)   ExecuteCommand(C->NotifyCommand, FALSE, NULL);
  1341.    if (C->NotifyType & NOTI_SOUND) PlaySound(C->NotifySound);
  1342. }
  1343. ///
  1344. /// TR_ProcessGETFunc
  1345. //  Downloads messages from a POP3 server
  1346. SAVEDS void TR_ProcessGETFunc(void)
  1347. {
  1348.    struct TransStat ts;
  1349.    struct Mail *mail;
  1350.  
  1351.    TR_TransStat_Init(&ts);
  1352.    if (ts.Msgs_Tot)
  1353.    {
  1354.       if (C->TransferWindow == 2) set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);
  1355.       TR_TransStat_Start(&ts);
  1356.       for (mail = G->TR->List; mail && !G->TR->Abort && !G->Error; mail = mail->Next)
  1357.       {
  1358.          TR_TransStat_NextMsg(&ts, mail->Index, mail->Position, mail->Size, GetStr(MSG_TR_Downloading));
  1359.          if (mail->Status & 1)
  1360.          {
  1361.             if (TR_LoadMessage(&ts, mail->Index))
  1362.             {
  1363.                G->TR->Stats.Downloaded++;
  1364.                if (C->AvoidDuplicates) TR_AppendUIDL(mail->UIDL);
  1365.                if (mail->Status & 2) TR_DeleteMessage(mail->Index);
  1366.             }
  1367.          }
  1368.          else if (mail->Status & 2)
  1369.          {
  1370.             TR_DeleteMessage(mail->Index);
  1371.          }
  1372.       }
  1373.       DisplayStatistics(FO_GetFolderByType(FT_INCOMING, NULL));
  1374.    }
  1375.    TR_GetMailFromNextPOP(FALSE, 0, 0);
  1376. }
  1377. MakeHook(TR_ProcessGETHook, TR_ProcessGETFunc);
  1378. ///
  1379. /// TR_GetMessageInfoFunc
  1380. //  Requests message header of a message selected by the user
  1381. SAVEDS void TR_GetMessageInfoFunc(void)
  1382. {
  1383.    int line;
  1384.    struct Mail *mail;
  1385.    get(G->TR->GUI.LV_MAILS, MUIA_NList_Active, &line);
  1386.    DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_GetEntry, line, &mail);
  1387.    TR_GetMessageDetails(mail, line);
  1388. }
  1389. MakeHook(TR_GetMessageInfoHook, TR_GetMessageInfoFunc);
  1390. ///
  1391. /// TR_CompleteMsgList
  1392. //  Gets details for messages on server
  1393. void TR_CompleteMsgList()
  1394. {
  1395.    struct TR_ClassData *tr = G->TR;
  1396.    struct Mail *mail = tr->GMD_Mail;
  1397.  
  1398.    if (C->PreSelection < 3) while (mail && !tr->Abort)
  1399.    {
  1400.       if (tr->Pause) return;
  1401.       if (tr->Start) { TR_ProcessGETFunc(); return; }
  1402.       if (C->PreSelection != 1 || mail->Size >= C->WarnSize*1024) TR_GetMessageDetails(mail, tr->GMD_Line++);
  1403.       mail = mail->Next;
  1404.    }
  1405.    set(G->TR->GUI.BT_PAUSE, MUIA_Disabled, TRUE);
  1406.    DoMethod(tr->GUI.BT_START, MUIM_KillNotify, MUIA_Pressed);
  1407.    DoMethod(tr->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_ProcessGETHook);
  1408.    DoMethod(tr->GUI.BT_QUIT , MUIM_KillNotify, MUIA_Pressed);
  1409.    DoMethod(tr->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_AbortGETHook);
  1410.    if (tr->Abort) TR_AbortGETFunc();
  1411. }
  1412. ///
  1413. /// TR_PauseFunc
  1414. //  Pauses or resumes message download
  1415. SAVEDS ASM void TR_PauseFunc(REG(a1) int *arg)
  1416. {
  1417.    BOOL pause = *arg;
  1418.  
  1419.    set(G->TR->GUI.BT_RESUME, MUIA_Disabled, !pause);
  1420.    set(G->TR->GUI.BT_PAUSE,  MUIA_Disabled, pause);
  1421.    if (pause) return;
  1422.    G->TR->Pause = FALSE;
  1423.    TR_CompleteMsgList();
  1424. }
  1425. MakeHook(TR_PauseHook, TR_PauseFunc);
  1426. ///
  1427.  
  1428. /*** GUI ***/
  1429. /// TR_LV_DspFunc
  1430. //  Message listview display hook
  1431. SAVEDS ASM long TR_LV_DspFunc(REG(a0) struct Hook *hook, REG(a2) char **array, REG(a1) struct Mail *entry)
  1432. {
  1433.    if (entry)
  1434.    {
  1435.       static char dispfro[SIZE_DEFAULT], dispsta[SIZE_DEFAULT], dispsiz[SIZE_SMALL], dispdate[32];
  1436.       struct Person *pe = &entry->From;
  1437.       sprintf(array[0] = dispsta, "%3ld ", entry->Index);
  1438.       if (entry->Status & 1) strcat(dispsta, "\033o[10]");
  1439.       if (entry->Status & 2) strcat(dispsta, "\033o[9]");
  1440.       if (entry->Size >= C->WarnSize<<10) strcat(dispsiz, MUIX_PH);
  1441.       array[1] = dispsiz; *dispsiz = 0;
  1442.       FormatSize(entry->Size, dispsiz);
  1443.       stccpy(array[2] = dispfro, AddrName((*pe)), SIZE_DEFAULT);
  1444.       array[3] = entry->Subject;
  1445.       array[4] = dispdate; *dispdate = 0;
  1446.       if (entry->Date.ds_Days) stccpy(dispdate, DateStamp2String(&entry->Date, C->SwatchBeat ? DSS_DATEBEAT : DSS_DATETIME), 32);
  1447.    }
  1448.    else
  1449.    {
  1450.       array[0] = GetStr(MSG_MA_TitleStatus);
  1451.       array[1] = GetStr(MSG_Size);
  1452.       array[2] = GetStr(MSG_From);
  1453.       array[3] = GetStr(MSG_Subject);
  1454.       array[4] = GetStr(MSG_Date);
  1455.       
  1456.    }
  1457.    return 0;
  1458. }
  1459. MakeHook(TR_LV_DspFuncHook,TR_LV_DspFunc);
  1460. ///
  1461. /// TR_New
  1462. //  Creates transfer window
  1463. struct TR_ClassData *TR_New(int TRmode)
  1464. {
  1465.    struct TR_ClassData *data;
  1466.  
  1467.    if (data = calloc(1,sizeof(struct TR_ClassData)))
  1468.    {
  1469.       APTR bt_all = NULL, bt_none = NULL, bt_loadonly = NULL, bt_loaddel = NULL, bt_delonly = NULL, bt_leave = NULL;
  1470.       APTR gr_sel, gr_proc, gr_win;
  1471.       BOOL fullwin = (TRmode == TR_GET || TRmode == TR_IMPORT);
  1472.  
  1473.       
  1474.       gr_proc = ColGroup(2), GroupFrameT(GetStr(MSG_TR_Status)),
  1475.          Child, data->GUI.TX_STATS = TextObject,
  1476.             MUIA_Text_Contents, GetStr(MSG_TR_TransferStats0),
  1477.             MUIA_Background,MUII_TextBack,
  1478.             MUIA_Frame     ,MUIV_Frame_Text,
  1479.             MUIA_Text_PreParse, MUIX_C,
  1480.          End,
  1481.          Child, VGroup,
  1482.             Child, data->GUI.GA_COUNT = GaugeObject,
  1483.                GaugeFrame,
  1484.                MUIA_Gauge_Horiz   ,TRUE,
  1485.                MUIA_Gauge_InfoText,GetStr(MSG_TR_MessageGauge0),
  1486.             End,
  1487.             Child, data->GUI.GA_BYTES = GaugeObject,
  1488.                GaugeFrame,
  1489.                MUIA_Gauge_Horiz   ,TRUE,
  1490.                MUIA_Gauge_InfoText,GetStr(MSG_TR_BytesGauge0),
  1491.             End,
  1492.          End,
  1493.          Child, data->GUI.TX_STATUS = TextObject,
  1494.             MUIA_Background,MUII_TextBack,
  1495.             MUIA_Frame     ,MUIV_Frame_Text,
  1496.          End,
  1497.          Child, data->GUI.BT_ABORT = MakeButton(GetStr(MSG_TR_Abort)),
  1498.       End;
  1499.       if (fullwin)
  1500.       {
  1501.          data->GUI.GR_LIST = VGroup, GroupFrameT(TRmode==TR_IMPORT ? GetStr(MSG_TR_MsgInFile) : GetStr(MSG_TR_MsgOnServer)),
  1502.             MUIA_ShowMe, TRmode==TR_IMPORT || C->PreSelection>=2,
  1503.             Child, NListviewObject,
  1504.                MUIA_CycleChain,1,
  1505.                MUIA_NListview_NList, data->GUI.LV_MAILS = NListObject,
  1506.                   MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
  1507.                   MUIA_NList_Format        , "W=-1 BAR,W=-1 MACW=9 P=\33r BAR,MICW=20 BAR,MICW=16 BAR,MICW=9 MACW=15",
  1508.                   MUIA_NList_DisplayHook   , &TR_LV_DspFuncHook,
  1509.                   MUIA_NList_AutoVisible   , TRUE,
  1510.                   MUIA_NList_Title         , TRUE,
  1511.                   MUIA_NList_TitleSeparator, TRUE,
  1512.                   MUIA_NList_DoubleClick   , TRUE,
  1513.                   MUIA_NList_MinColSortable, 0,
  1514.                   MUIA_Font, C->FixedFontList ? MUIV_NList_Font_Fixed : MUIV_NList_Font,
  1515.                   MUIA_ContextMenu         , NULL,
  1516.                   MUIA_NList_Exports, MUIV_NList_Exports_Cols,
  1517.                   MUIA_NList_Imports, MUIV_NList_Imports_Cols,
  1518.                   MUIA_ObjectID, MAKE_ID('N','L','0','4'),
  1519.                End,
  1520.             End,
  1521.          End;
  1522.          gr_sel = VGroup, GroupFrameT(GetStr(MSG_TR_Control)),
  1523.             Child, ColGroup(5),
  1524.                Child, bt_all = MakeButton(GetStr(MSG_TR_All)),
  1525.                Child, bt_loaddel = MakeButton(GetStr(MSG_TR_DownloadDelete)),
  1526.                Child, bt_leave = MakeButton(GetStr(MSG_TR_Leave)),
  1527.                Child, HSpace(0),
  1528.                Child, data->GUI.BT_PAUSE = MakeButton(GetStr(MSG_TR_Pause)),
  1529.                Child, bt_none = MakeButton(GetStr(MSG_TR_Clear)),
  1530.                Child, bt_loadonly = MakeButton(GetStr(MSG_TR_DownloadOnly)),
  1531.                Child, bt_delonly = MakeButton(GetStr(MSG_TR_DeleteOnly)),
  1532.                Child, HSpace(0),
  1533.                Child, data->GUI.BT_RESUME = MakeButton(GetStr(MSG_TR_Resume)),
  1534.             End,
  1535.             Child, ColGroup(2),
  1536.                Child, data->GUI.BT_START = MakeButton(GetStr(MSG_TR_Start)),
  1537.                Child, data->GUI.BT_QUIT = MakeButton(GetStr(MSG_TR_Abort)),
  1538.             End,
  1539.          End;
  1540.          gr_win = VGroup,
  1541.             Child, data->GUI.GR_LIST,
  1542.             Child, data->GUI.GR_PAGE = PageGroup,
  1543.                Child, gr_sel,
  1544.                Child, gr_proc,
  1545.             End,
  1546.          End;
  1547.       }
  1548.       else gr_win = gr_proc;
  1549.       data->GUI.WI = WindowObject,
  1550.          MUIA_Window_ID, MAKE_ID('T','R','A','0'+TRmode-TR_IMPORT),
  1551.          MUIA_Window_CloseGadget, FALSE,
  1552.          MUIA_Window_Activate, (TRmode == TR_IMPORT || TRmode == TR_EXPORT),
  1553.          MUIA_HelpNode, "TR_W",
  1554.          WindowContents, gr_win,
  1555.       End;
  1556.       if (data->GUI.WI)
  1557.       {
  1558.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  1559.          SetHelp(data->GUI.TX_STATUS,MSG_HELP_TR_TX_STATUS);
  1560.          SetHelp(data->GUI.BT_ABORT ,MSG_HELP_TR_BT_ABORT);
  1561.          if (fullwin)
  1562.          {
  1563.             set(data->GUI.BT_RESUME, MUIA_Disabled, TRUE);
  1564.             if (TRmode == TR_IMPORT)
  1565.             {
  1566.                set(data->GUI.BT_PAUSE, MUIA_Disabled, TRUE);
  1567.                set(bt_delonly        , MUIA_Disabled, TRUE);
  1568.                set(bt_loaddel        , MUIA_Disabled, TRUE);
  1569.                DoMethod(data->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_ProcessIMPORTHook);
  1570.                DoMethod(data->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_AbortIMPORTHook);
  1571.             }
  1572.             else
  1573.             {
  1574.                set(data->GUI.GR_PAGE, MUIA_Group_ActivePage, 1);
  1575.                DoMethod(data->GUI.BT_RESUME,MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_PauseHook,0);
  1576.                DoMethod(data->GUI.BT_PAUSE ,MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_PauseHook,1);
  1577.                DoMethod(data->GUI.BT_PAUSE, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Pause));
  1578.                DoMethod(data->GUI.LV_MAILS ,MUIM_Notify, MUIA_NList_DoubleClick,TRUE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_GetMessageInfoHook);
  1579.                DoMethod(bt_delonly,         MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,2);
  1580.                DoMethod(bt_loaddel,         MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,3);
  1581.                DoMethod(data->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Start));
  1582.                DoMethod(data->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Abort));
  1583.             }
  1584.             DoMethod(bt_loadonly,        MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,1);
  1585.             DoMethod(bt_leave,           MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,0);
  1586.             DoMethod(bt_all,             MUIM_Notify, MUIA_Pressed, FALSE, data->GUI.LV_MAILS, 4, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_On, NULL);
  1587.             DoMethod(bt_none,            MUIM_Notify, MUIA_Pressed, FALSE, data->GUI.LV_MAILS, 4, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);
  1588.             DoMethod(data->GUI.LV_MAILS, MUIM_NList_UseImage, G->MA->GUI.BC_STAT[9], 9, 0);
  1589.             DoMethod(data->GUI.LV_MAILS, MUIM_NList_UseImage, G->MA->GUI.BC_STAT[10], 10, 0);
  1590.          }
  1591.          DoMethod(data->GUI.BT_ABORT, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Abort));
  1592.          MA_ChangeTransfer(FALSE);
  1593.          return data;
  1594.       }
  1595.       free(data);
  1596.    }
  1597.    return NULL;
  1598. }
  1599. ///
  1600.